﻿using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using 纸片人.AttributeUsageFloder;
using 纸片人.Shaders;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{
    [LastModified("2022-5-12", "create FreeTransformShaderPage.xaml")]
    [PageType("gpg", "自由变换")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class FreeTransformShaderPage : Page
    {
        //图像大小和画布大小
        int imageWidth;
        int imageHeight;
        int width;
        int height;
        //原图和最终渲染的图像
        CanvasBitmap bitmap;
        CanvasRenderTarget renderTarget;
        PixelShaderEffect freeTrans;
        //四个点的相对位置
        Vector2 ltPos = new Vector2(0, 0);
        Vector2 rtPos = new Vector2(1, 0);
        Vector2 lbPos = new Vector2(0, 1);
        Vector2 rbPos = new Vector2(1, 1);

        //偏移和缩放后的大小
        float ox;
        float oy;
        float sw;
        float sh;
        byte[] ftShaderCode;
        public FreeTransformShaderPage()
        {
            this.InitializeComponent();

            //设置点的位置
            Action<Vector2> setPointPos = (e) =>
            {
                Canvas.SetLeft(e2, e.X); ;
                Canvas.SetTop(e2, e.Y);
            };

            Func<Vector2, Vector2, float, float, bool> isInsideLine = (Vector2 s, Vector2 e, float x, float y) =>
                  {

                      return ((x >= s.X && x <= e.X)
                          || (x >= e.X && x <= s.X))
                          && ((y >= s.Y && y <= e.Y)
                              || (y >= e.Y && y <= s.Y));


                   
                  };

            c2.PointerMoved += (s, e) =>
            {
                int tw = 200;
                int th = 200;

                //鼠标当前位置
                Vector2 cp = e.GetCurrentPoint(this.c2).Position.ToVector2();
                setPointPos(cp);

                //四个点的位置
                var ltp = new Point(t.X1, t.Y1).ToVector2();
                var rtp = new Point(t.X2, t.Y2).ToVector2();
                var lbp = new Point(b.X1, b.Y1).ToVector2();
                var rbp = new Point(b.X2, b.Y2).ToVector2();

                //新的矩形大小和位置
                var nw = Math.Max(Math.Abs(ltp.X - rtp.X), Math.Abs(lbp.X - rbp.X));
                var nh = Math.Max(Math.Abs(ltp.Y - lbp.Y), Math.Abs(rtp.Y - rbp.Y));

                Vector2 xy = ltp - rbp;
                Vector2 xy1 = cp - xy;
                Vector2 xy2 = cp + xy;
                Vector2 yx = lbp - rtp;
                Vector2 yx1 = cp - yx;
                Vector2 yx2 = cp + yx;

                Vector2 xyf = GetIntersection(xy1, xy2, lbp, rtp);
                Vector2 yxf = GetIntersection(yx1, yx2, ltp, rbp);

                float xyScale = Vector2.Distance(xyf, lbp) / Vector2.Distance(lbp, rtp); // 0~1
                float xyRScale = 1 - xyScale; // 1~0 

                float yxScale = Vector2.Distance(yxf, ltp) / Vector2.Distance(ltp, rbp); // 0~1
                float yxRScale = 1 - yxScale; // 1~0

               
                // Vector (0, 0) (1, 1)  (0, 1) (1, 0)
                // 单元向量正方形之内
                // 中点
                // 点
                // 以及点与两条对角线的平行线的互相的交点
                // 构成一个长方形
                Vector2 xyP = new Vector2(0, 1) * xyRScale + new Vector2(1, 0) * xyScale;
                Vector2 yxP = new Vector2(0, 0) * yxRScale + new Vector2(1, 1) * yxScale;
                Vector2 center = new Vector2(0.5f, 0.5f);
                Vector2 p1 = new Vector2
                {
                    X = center.X + yxP.Y - xyP.Y,
                    Y = center.Y + yxP.X - xyP.X,
                };

                //原图位置
                // Tagret
                Vector2 p2 = p1 * new Vector2(200, 200);
                Canvas.SetLeft(e1, p2.X - 5);
                Canvas.SetTop(e1, p2.Y - 5);

            };

        }

        //获取两直线交点，
        public static Vector2 GetIntersection(Vector2 lineAStart, Vector2 lineAEnd, Vector2 lineBStart, Vector2 lineBEnd)
        {
            float x1 = lineAStart.X, y1 = lineAStart.Y;
            float x2 = lineAEnd.X, y2 = lineAEnd.Y;

            float x3 = lineBStart.X, y3 = lineBStart.Y;
            float x4 = lineBEnd.X, y4 = lineBEnd.Y;

            //equations of the form x=c (two vertical lines)
            if (x1 == x2 && x3 == x4 && x1 == x3)
            {
                return Vector2.Zero;
            }

            //equations of the form y=c (two horizontal lines)
            if (y1 == y2 && y3 == y4 && y1 == y3)
            {
                return Vector2.Zero;
            }

            //equations of the form x=c (two vertical lines)
            if (x1 == x2 && x3 == x4)
            {
                return Vector2.Zero;
            }

            //equations of the form y=c (two horizontal lines)
            if (y1 == y2 && y3 == y4)
            {
                return Vector2.Zero;
            }
            float x, y;

            if (x1 == x2)
            {
                float m2 = (y4 - y3) / (x4 - x3);
                float c2 = -m2 * x3 + y3;

                x = x1;
                y = c2 + m2 * x1;
            }
            else if (x3 == x4)
            {
                float m1 = (y2 - y1) / (x2 - x1);
                float c1 = -m1 * x1 + y1;

                x = x3;
                y = c1 + m1 * x3;
            }
            else
            {
                //compute slope of line 1 (m1) and c2
                float m1 = (y2 - y1) / (x2 - x1);
                float c1 = -m1 * x1 + y1;

                //compute slope of line 2 (m2) and c2
                float m2 = (y4 - y3) / (x4 - x3);
                float c2 = -m2 * x3 + y3;

                //solving equations (3) & (4) => x = (c1-c2)/(m2-m1)
                //plugging x value in equation (4) => y = c2 + m2 * x
                x = (c1 - c2) / (m2 - m1);
                y = c2 + m2 * x;

                //          if (!(-m1 * x + y == c1
                //              && -m2 * x + y == c2))
                //          {
                //              return Vector2.Zero;
                //          }
            }

            if (IsInsideLine(lineAStart, lineAEnd, x, y) &&
                IsInsideLine(lineBStart, lineBEnd, x, y))
            {
                return new Vector2(x, y);
            }

            //return default null (no intersection)
            return Vector2.Zero;
        }
        private static bool IsInsideLine(Vector2 start, Vector2 end, float x, float y)
        {
            return ((x >= start.X && x <= end.X)
                || (x >= end.X && x <= start.X))
                && ((y >= start.Y && y <= end.Y)
                    || (y >= end.Y && y <= start.Y));
        }


        async Task LoacalShaderCode()
        {
            //ftShaderCode = await ShaderExtensions.LoadAsync(ShaderType.Transform);
            ////初始化着色器
            //freeTrans = new PixelShaderEffect(ftShaderCode)
            //{
            //};
        }

        private async void selectPicture_Click(object sender, RoutedEventArgs e)
        {
            bitmap = await Function.SelectImageAsync();
            if (bitmap == null)
                return;

            renderTarget = new CanvasRenderTarget(ca, bitmap.Size);
            freeTrans.Source1 = bitmap;
            initialRect();
        }



        void initialRect()
        {
            if (bitmap == null)
                return;
            InitInfo();
            ca.Invalidate();
            SetThumbPos();

        }
        void InitInfo()
        {
            //画布大小
            double cw = canvas.ActualWidth;
            double ch = canvas.ActualHeight;
            width = (int)cw;
            height = (int)ch;
            imageWidth = (int)bitmap.Size.Width;
            imageHeight = (int)bitmap.Size.Height;
            float f = (float)(Math.Min((float)width / (float)imageWidth, (float)height / (float)imageHeight));
            sw = imageWidth * f;
            sh = imageHeight * f;
            ox = (float)(width - sw) / 2f;
            oy = (float)(height - sh) / 2f;
        }

        void SetThumbPos()
        {
            ltThumb.Translation = new Vector3(ox + ltPos.X * sw - 5, oy + ltPos.Y * sh - 5, 0);
            rtThumb.Translation = new Vector3(ox + rtPos.X * sw - 5 - 100, oy + rtPos.Y * sh - 5, 0);
            lbThumb.Translation = new Vector3(ox + lbPos.X * sw - 5, oy + lbPos.Y * sh - 5, 0);
            rbThumb.Translation = new Vector3(ox + rbPos.X * sw - 5 - 100, oy + rbPos.Y * sh - 5, 0);
            ca.Invalidate();
        }


        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Thumb thumb = sender as Thumb;
            float ox = (float)e.HorizontalChange;
            float oy = (float)e.VerticalChange;
            float oxp = ox / sw;
            float oyp = oy / sh;
            if (thumb == ltThumb)
            {
                ltPos.X += oxp;
                ltPos.Y += oyp;
            }
            else if (thumb == rtThumb)
            {
                rtPos.X += oxp;
                rtPos.Y += oyp;
            }

            else if (thumb == lbThumb)
            {
                lbPos.X += oxp;
                lbPos.Y += oyp;
            }
            else
            {
                rbPos.X += oxp;
                rbPos.Y += oyp;
            }
            SetThumbPos();

        }



        private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
        {


        }

        private void reset_Click(object sender, RoutedEventArgs e)
        {
            initialRect();
        }

        private void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            double cw = canvas.ActualWidth;
            double ch = canvas.ActualHeight;
            width = (int)cw;
            height = (int)ch;
            SetThumbPos();
        }

        private void canvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            //if (freeTrans.Source1 != null);
            //{
            //    //var lt = freeTrans.Properties["ltPos"];
            //    //var rt = freeTrans.Properties["rtPos"];
            //    //freeTrans.Properties["ltPos"] = ltPos * new Vector2(imageWidth, imageHeight);
            //    //freeTrans.Properties["rtPos"] = rtPos * new Vector2(imageWidth, imageHeight);
            //    //freeTrans.Properties["lbPos"] = lbPos * new Vector2(imageWidth, imageHeight);
            //    //freeTrans.Properties["rbPos"] = rbPos * new Vector2(imageWidth, imageHeight);
            //    //TTTTTT ttttt = new TTTTTT(ltPos * new Vector2(imageWidth, imageHeight), rtPos * new Vector2(imageWidth, imageHeight), lbPos * new Vector2(imageWidth, imageHeight), rbPos * new Vector2(imageWidth, imageHeight));
            //    TTTTTT ttttt = new TTTTTT(ltPos , rtPos , rbPos , lbPos );
            //    freeTrans.Properties["LineA"]= ttttt.LineA;
            //    freeTrans.Properties["LineB"]= ttttt.LineB;
            //    freeTrans.Properties["MatrixUp"] = ttttt.MatrixUp;
            //    freeTrans.Properties["MatrixDown"] = ttttt.MatrixDown;
            //    //var v = freeTrans.GetBounds(ca);
            //    //using (var ds = renderTarget.CreateDrawingSession())
            //    //{
            //    //    ds.Clear(Colors.Transparent);
            //    //    ds.DrawImage(freeTrans);
            //    //}

                
                

            //    var te = Function.EvalBitmapCenter(width, height, imageWidth, imageHeight);
            //    te.Source = freeTrans;
            //    args.DrawingSession.DrawImage(te);
            //}
        }

        private void ca_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
        {
            args.TrackAsyncAction(LoacalShaderCode().AsAsyncAction());
        }
    }
}
